package org.msfj.gateserver.filters;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import org.msfj.authority.client.config.JwtConfig;
import org.msfj.common.annotation.Constants;
import org.msfj.common.enums.HttpCode;
import org.msfj.common.exception.TokenErrorException;
import org.msfj.common.model.CommonResult;
import org.msfj.common.util.jwt.IJWTInfo;
import org.msfj.common.util.jwt.JWTHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @Description: 前台会员token验证过滤器
 * @Author: like
 * @Date: 2017-12-21 11:47
 * @Version: 1.0
 * @Created in idea by autoCode
 */
@Component
public class MemberTokenCheckGatewayFilterFactory extends AbstractGatewayFilterFactory {

    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    JwtConfig jwtConfig;

    @Autowired
    RedisTemplate<String, Object> redisTemplate;

    @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> {
            try {
                String memberToken = getToken(exchange);
                IJWTInfo member;
                if (StrUtil.isBlank(memberToken)) {
                    throw new TokenErrorException("用户token为空");
                } else {
                    member = JWTHelper.getInfoFromToken(memberToken, jwtConfig.getPubKeyPath());
                }
                if (member != null) {
                    Object invlideToken = redisTemplate.opsForValue().get(member.getUniqueName());
                    if (ObjectUtil.isNotNull(invlideToken) && memberToken.equals(invlideToken.toString())) {
                        throw new TokenErrorException("用户token已过期");
                    } else {
                        exchange.getRequest().getHeaders().add(Constants.CONTEXT_KEY_MEMBER_ID, member.getId());
                        if (member.getBuffer() <= jwtConfig.getMemberBuffer()) {
                            exchange.getResponse().getHeaders().add(Constants.REFRESH_TOKEN, "true");
                        }
                    }
                }
            } catch (Exception e) {
                ServerHttpResponse response = exchange.getResponse();
                //设置body
                CommonResult commonResult = CommonResult.build(HttpCode.USER_TOKEN_ERROR_CODE.value(), e.getMessage(), null);
                DataBuffer bodyDataBuffer = response.bufferFactory().wrap(JSONUtil.toJsonStr(commonResult).getBytes());
                return response.writeWith(Mono.just(bodyDataBuffer));
            }
            return chain.filter(exchange);
        };
    }

    /**
     * 返回session中的用户信息
     *
     * @param exchange
     * @return
     */
    private String getToken(ServerWebExchange exchange) throws Exception {
        String authToken = exchange.getRequest().getHeaders().getFirst(jwtConfig.getMemberTokenHeader());
        if (StrUtil.isBlank(authToken)) {
            MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
            authToken = queryParams.getFirst("token");
        }
        if (StrUtil.isBlank(authToken)) {
            MultiValueMap<String, HttpCookie> cookies = exchange.getRequest().getCookies();
            HttpCookie cookie = cookies.getFirst(jwtConfig.getMemberTokenHeader());
            authToken = cookie != null ? cookie
                    .getValue() : null;
        }
        return authToken;
    }
}
